﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ServerFramework.Db;


namespace ServerFramework.ORM
{
    /// <summary>
    /// 数据实体缓存基类
    /// </summary>
    public abstract class DataEntityCache
    {
        protected Dictionary<string, DataContainer> _dataCache = new Dictionary<string, DataContainer>();
        
        /// <summary>
        /// 初始化
        /// </summary>
        protected virtual void Init()
        {
        }

        /// <summary>
        /// 获取所有的数据实例
        /// </summary>
        /// <returns></returns>
        public List<DataEntityBase> GetAllEntitys()
        {
            List<DataEntityBase> entitys = new List<DataEntityBase>();
            foreach(var c in _dataCache)
            {
                entitys.AddRange(c.Value.GetAllEntitys());
            }
            return entitys;
        }

        /// <summary>
        /// 由于初始化时已经确定了容器，所有后面不用加锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        protected DataContainer GetContainer<T>()
        {
            string key = typeof(T).Name;
            if (!_dataCache.ContainsKey(key))
            {
                _dataCache.Add(key, new DataContainer());
            }
            return _dataCache[key];
        }

        /// <summary>
        /// 创建容器
        /// </summary>
        /// <param name="baseType"></param>
        /// <param name="isCache"></param>
        protected void CreateContainers(Type baseType,bool isLoadData = false)
        {
            List<Type> types = ORMHelper.GetTypesFromCurrAssemblyByBase(baseType);
            for (int i = 0; i < types.Count; ++i)
            {
                Type type = types[i];
                //检查数据库
                DataContainer container = new DataContainer();
                _dataCache.Add(type.Name, container);
                if (isLoadData)
                {
                    List<DataEntityBase> dbDatas = ORMHelper.GetDbEntityList(type);
                    for (int j = 0; j < dbDatas.Count; ++j)
                    {
                        DataEntityBase dt = dbDatas[j];
                        if (dt != null)
                        {
                            container.Add(dt.id, dt);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 找一条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual T FindKey<T>(long id) where T : DataEntityBase, new()
        {
            T t = null;
            t = GetContainer<T>().Get<T>(id);
            if (t != null)
            {
                t.UseTime = DateTime.Now;
                return t;
            }
            //再从数据库查找
            if (t == null)
            {
                DbHelper.ExecuteQuery(DataEntityBase.GetDbName<T>(), p =>
                {
                    t = ORMHelper.GetDbEntity<T>(p, id);
                    if (t != null)
                    {
                        t.UseTime = DateTime.Now;
                        GetContainer<T>().Add(t.id, t);
                    }
                });
            }
            return t;
        }
       
        /// <summary>
        /// 找一组数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ids"></param>
        /// <returns></returns>
        public virtual List<T> FindKeys<T>(List<long> ids) where T : DataEntityBase, new()
        {
            if (ids.Count == 0)
            {
                return new List<T>();
            }
            List<T> list = null;
            list = GetContainer<T>().Get<T>(ids);
            if (list.Count != 0)
            {
                return list;
            }
            list = ORMHelper.GetDbEntityList<T>(ids);
            for (int i = 0; i < list.Count; ++i)
            {
                DataEntityBase t = list[i];
                GetContainer<T>().Add(t.id, t);
            }
            return list;
        }

        /// <summary>
        /// 找所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ids"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T>() where T : DataEntityBase, new()
        {
            List<T> list = null;
            list = GetContainer<T>().GetAll<T>();
            return list;
        }

        /// <summary>
        /// 立即从数据库中刷 DBData -> Cache 中
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public DataEntityCache ReflushAll<T>()
        {
            //从数据库获取数据
            List<DataEntityBase> modelsInDB = ORMHelper.GetDbEntityList(typeof(T));
            //将 data -> cache
            DataContainer currentContainer = GetContainer<T>();
            currentContainer.Clear();

            string key = typeof(T).Name;
            if (_dataCache.ContainsKey(key))
            {
                _dataCache.Remove(key);
            }
            for (int i = 0; i < modelsInDB.Count; ++i)
            {
                currentContainer.Add(modelsInDB[i].id, modelsInDB[i]);
            }

            _dataCache.Add(key, currentContainer);

            return this;
        }

        /// <summary>
        /// 条件查找
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="match"></param>
        /// <returns></returns>
        public virtual List<T> FindAll<T>(Predicate<T> match) where T : DataEntityBase, new()
        {
            List<T> list = FindAll<T>();
            return list.FindAll(match);
        }

        /// <summary>
        /// 加一条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public virtual void AddEntity<T>(T t) where T : DataEntityBase, new()
        {
            t.UseTime = DateTime.Now;
            t.SetState(EEntityState.Add);
            GetContainer<T>().Add<T>(t.id, t);
        }

        /// <summary>
        /// 删除一条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public virtual void RemoveEntity<T>(T t) where T : DataEntityBase, new()
        {
            t.SetState(EEntityState.Delete);
            GetContainer<T>().Remove<T>(t.id);
            DbEntityManager.Instance.AddRemoveEntity(t);
        }


        /// <summary>
        /// 删除一组数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public virtual void RemoveEntitys<T>(List<T> ts) where T : DataEntityBase, new()
        {
            foreach(var t in ts)
            {
                RemoveEntity<T>(t);
            }
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public virtual void Set<T>(T t) where T : DataEntityBase, new()
        {
            t.UseTime = DateTime.Now;
            t.SetState(EEntityState.Update);
        }

        /// <summary>
        /// 移除所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public virtual void RemoveAll<T>() where T : DataEntityBase, new()
        {
            var list = FindAll<T>();
            GetContainer<T>().Clear();
            foreach(var t in list)
            {
                RemoveEntitys(list);
            }
        }

        /// <summary>
        /// 条件移除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="match"></param>
        public virtual void RemoveAll<T>(Predicate<T> match) where T : DataEntityBase, new()
        {
            List<T> list = FindAll<T>(match);
            RemoveEntitys(list);
        }


        /// <summary>
        /// 获取所有的keys
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual List<long> GetKeys<T>() where T : DataEntityBase
        {
            List<long> list = GetContainer<T>().GetKeys<T>();
            if(list.Count == 0)
            {
                DbHelper.ExecuteQuery(DataEntityBase.GetDbName<T>(), p =>
                {
                    long tempId = 0;
                    string sql = string.Format("select ID from {0}", typeof(T).Name);
                    if (p.ExecuteQuery(sql))
                    {
                        while (p.Read())
                        {
                            p.Read(ref tempId);
                            list.Add(tempId);
                        }
                    }
                });
            }
            return list;
        }


        /// <summary>
        /// 获取某页的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pageIndex"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public List<T> GetPageList<T>(int pageIndex, int count) where T : DataEntityBase
        {
            var temp = GetContainer<T>().GetAll<T>();
            int startRank = pageIndex * count + 1;
            int endRank = (pageIndex + 1) * count;
            List<T> list = new List<T>();
            for (int i = 0; i < temp.Count; ++i)
            {
                var entity = temp[i];
                if (entity.Rank >= startRank && entity.Rank <= endRank)
                {
                    if (list.Count < count)
                    {
                        list.Add(entity);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            list.Sort();
            return list;
        }

    }
}
